package com.freeter.luceneUtil;

import java.lang.reflect.Method;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

/**
 * 工具类
 * 
 * @author AdminTC
 */
public class LuceneUtil {

	private static Directory directory;
	private static Version version;
	private static Analyzer analyzer;
	private static Map<String, Analyzer> fieldAnalyzers;
	static {
		try {
			directory = FSDirectory.open(Paths.get("E:/Index"));
			version = Version.LUCENE_7_1_0;

			analyzer = new StandardAnalyzer();

		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	public static Directory getDirectory() {
		return directory;
	}

	public static Version getVersion() {
		return version;
	}

	public static Analyzer getAnalyzer() {
		return analyzer;
	}

	public static Analyzer fieldAnalyze(String fieldName) {
		fieldAnalyzers = new HashMap();
		fieldAnalyzers.put(fieldName, new PatternAnalyzer());
		analyzer = new PerFieldAnalyzerWrapper(new StandardAnalyzer(), fieldAnalyzers);
		return analyzer;
	}

	public static Analyzer fieldAnalyze(String fieldName, Analyzer analyzer) {
		fieldAnalyzers = new HashMap();
		fieldAnalyzers.put(fieldName, analyzer);
		analyzer = new PerFieldAnalyzerWrapper(new StandardAnalyzer(), fieldAnalyzers);
		return analyzer;
	}

	/**
	 * 根据关键字，批量查询记录
	 * 
	 * @param start
	 *            从第几条记录的索引号开始查询，索引号从0开始
	 * @param size
	 *            最多查询几条记录，不满足最多数目时，以实际为准
	 * @return 集合
	 */
	public List<Document> findAll(String keywords, String col, int start, int size) throws Exception {
		List<Document> documents = new ArrayList<Document>();
		/*
		 * QueryParser queryParser = new
		 * QueryParser(col,LuceneUtil.getAnalyzer()); Query query =
		 * queryParser.parse(keywords);
		 */
		keywords = "*" + keywords + "*";
		Query query = new WildcardQuery(new Term(col, keywords));
		DirectoryReader ireader = DirectoryReader.open(directory);
		IndexSearcher indexSearcher = new IndexSearcher(ireader);
		TopDocs topDocs = indexSearcher.search(query, 100);

		// 小技巧
		int middle = Math.min(start + size, Long.valueOf(topDocs.totalHits).intValue());
		for (int i = start; i < middle; i++) {
			ScoreDoc scoreDoc = topDocs.scoreDocs[i];
			int no = scoreDoc.doc;
			Document document = indexSearcher.doc(no);
			documents.add(document);

		}

		return documents;
	}

	// 不让外界new该帮助类
	private LuceneUtil() {
	}

	// 将JavaBean转成Document对象
	public static Document javabean2document(Object obj) throws Exception {
		// 创建Docuemnt对象
		Document document = new Document();
		// 获取obj引用的对象字节码
		Class clazz = obj.getClass();
		// 通过对象字节码获取私有的属性
		java.lang.reflect.Field[] reflectFields = clazz.getDeclaredFields();
		// 迭代
		for (java.lang.reflect.Field reflectField : reflectFields) {
			// 强力反射
			reflectField.setAccessible(true);
			// 获取属性名，id/title/content
			String name = reflectField.getName();
			// 人工拼接方法名
			String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
			// 获取方法，例如：getId()/getTitle()/getContent()
			Method method = clazz.getMethod(methodName, null);
			// 执行方法

			Object o = method.invoke(obj, null);
			if (o == null) {
				continue;
			}
			String value = o.toString();
			// 加入到Document对象中去，这时javabean的属性与document对象的属性相同
			if (StringUtils.isNoneEmpty(value))
				document.add(new Field(name, value, TextField.TYPE_STORED));
		}
		// 返回document对象
		return document;
	}

	// 将Document对象转成JavaBean对象
	public static Object document2javabean(Document document, Class clazz) throws Exception {
		Object obj = clazz.newInstance();
		java.lang.reflect.Field[] reflectFields = clazz.getDeclaredFields();
		for (java.lang.reflect.Field reflectField : reflectFields) {
			reflectField.setAccessible(true);
			String name = reflectField.getName();// id/title/content
			String value = document.get(name);// 1/培训/传智是一家培训机构
			BeanUtils.setProperty(obj, name, value);// 封装javabean对应的属性中去，通过setXxx()方法
		}
		return obj;
	}

	public PageInfo getPage(String keywords, String col, int page) throws Exception {
		PageInfo pageInfo = new PageInfo();

		// 封装当前页号
		pageInfo.setPage(page);

		// 封装总记录数
		int allRecordNO = getAllRecord(col, keywords);
		pageInfo.setTotal(allRecordNO);

		// 封装总页数
		int allPageNO = 0;
		if (pageInfo.getTotal() % pageInfo.getPagesize() == 0) {
			allPageNO = pageInfo.getTotal() / pageInfo.getPagesize();
		} else {
			allPageNO = pageInfo.getTotal() / pageInfo.getPagesize() + 1;
		}
		pageInfo.setPage(allPageNO);

		// 封装内容
		int size = pageInfo.getPagesize();
		int start = (pageInfo.getPage() - 1) * size;
		List dataList = findAll(col, keywords, start, size);
		pageInfo.setDataList(dataList);

		return pageInfo;
	}

	/**
	 * 根据关键字，获取总记录数
	 * 
	 * @return 总记录数
	 */
	public int getAllRecord(String col, String keywords) throws Exception {
		/*
		 * QueryParser queryParser = new
		 * QueryParser(col,LuceneUtil.getAnalyzer()); Query query =
		 * queryParser.parse(keywords);
		 */
		keywords = "*" + keywords + "*";
		Query query = new WildcardQuery(new Term(col, keywords));
		DirectoryReader ireader = DirectoryReader.open(directory);
		IndexSearcher indexSearcher = new IndexSearcher(ireader);
		TopDocs topDocs = indexSearcher.search(query, 2);
		// 返回符合条件的真实总记录数，不受2的影响
		return Long.valueOf(topDocs.totalHits).intValue();
		// 返回符合条件的总记录数，受2的影响
		// return topDocs.scoreDocs.length;
	}
}
